package tpsi.pong;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map.Entry;

import org.xlightweb.IWebSocketConnection;
import org.xlightweb.IWebSocketHandler;
import org.xlightweb.TextMessage;

public class MyWebSocketHandler implements IWebSocketHandler {

	private GamesManager gamesManager;
	private PlayerManager playerManager;

	public MyWebSocketHandler() {
		this.gamesManager = new GamesManager();
		this.playerManager = new PlayerManager();
	}

	public void onConnect(IWebSocketConnection con) throws IOException {
		Player p = playerManager.cratePlayer();
		p.setConection(con);
		StringBuilder answer = new StringBuilder();
		answer.append(this.gamesManager.getGamesMsg());
		answer.append("\n");
		answer.append(p.getCIDMsg());
		TextMessage msg = new TextMessage(answer.toString());
		con.writeMessage(msg);
	}

	public void onDisconnect(IWebSocketConnection con) throws IOException {
		this.playerManager.clean();
		for (Iterator<Entry<Long, Player>> it = this.playerManager
				.getPlayersEntrySet().iterator(); it.hasNext();) {
			Entry<Long, Player> pair = it.next();
			Player p = pair.getValue();
			p.sendMsg("PONG\n0");
			Game g = null;
			if (p.isDisconnected() && ((g = p.getCurrentGame()) != null)) {
				p.setCurrentGame(null);
				g.removePlayer(p);
				if (g.getPlayersCount() <= 0)
					this.gamesManager.deleteGame(g.getName());
			}
		}
	}

	public void onMessage(IWebSocketConnection con) throws IOException {
		String anwser = processMessage(con);
		if (anwser != null) {
			TextMessage ret = new TextMessage(anwser);
			con.writeMessage(ret);
		}
	}

	/**
	 * Process incoming message.
	 * 
	 * @param s
	 *            Message string to process.
	 * @return Answer message if needed. Else null.
	 */
	private String processMessage(IWebSocketConnection con) throws IOException {
		TextMessage tm = con.readTextMessage();
		if (tm == null)
			return null;
		String[] str = tm.toString().split("\n");
		for (int i = 0; i < str.length; ++i) {
			if (str[i].isEmpty()
					&& !((i > 0) && str[i - 1].equalsIgnoreCase("GAMES")))
				return "ERROR\n0:Message not complete!.";
		}
		if (str[0].equalsIgnoreCase("PLAYER")) {
			String[] tab = str[1].split(":");
			Player p = null;
			try {
				p = this.playerManager.getPlayerById(Long.parseLong(tab[1]));
			} catch (NumberFormatException e) {
				return "ERROR\n1:Could not veryfy CID.";
			}
			if (p == null)
				return "ERROR\n1:Could not veryfy CID.";
			if (str[2].equalsIgnoreCase("PPOS")) {
				Game g = p.getCurrentGame();
				if (g == null)
					return "ERROR\n0:Joing game first, n00b?";
				Paddle pad = g.getPlayerPaddle(p);
				try {
					pad.setPaddlePos(str[3]);
					pad.setPaddleMove(PaddleMove.valueOf(str[5]));
					g.sendMsgToAll(tm.toString());
				} catch (Exception ex) {
					return "ERROR\n0:Error in data.";
				}
			} else if (str[2].equalsIgnoreCase("BPOS")) {
				Game g = p.getCurrentGame();
				if (g == null)
					return "ERROR\n0:WOOT?";
				if (p != g.getOwner())
					return "ERROR\n0:Not host.";
				try {
					g.setBallPos(str[3]);
					g.setBallSpeed(str[5]);
					Ball b = g.getBall();
					g.sendMsgToAll(b.getBMoveMsg());
				} catch (Exception ex) {
					return "ERROR\n0:Error in data.";
				}
			} else if (str[2].equalsIgnoreCase("HOST")) {
				p.setName(tab[0]);
				Game g = this.gamesManager.createGame(str[3], p);
				if (g == null)
					return "ERROR\n2:Could not create game. Try later or change game name.";
				StringBuilder sb = new StringBuilder();
				sb.append(str[0]);
				sb.append("\n");
				sb.append(str[1]);
				sb.append("\n");
				sb.append("JOIN\n");
				sb.append(str[3]);
				sb.append("\n");
				sb.append(g.getSTATEMsg());
				return sb.toString();
			} else if (str[2].equalsIgnoreCase("JOIN")) {
				p.setName(tab[0]);
				Game g = this.gamesManager.getGame(str[3]);
				g.playerStatusChanged();
				if (g == null)
					return "ERROR\n3:No souch game or full.";
				StringBuilder sb = new StringBuilder();
				sb.append(str[0]);
				sb.append("\n");
				sb.append(str[1]);
				sb.append("\n");
				sb.append("JOIN\n");
				sb.append(str[3]);
				sb.append("\n");
				sb.append(g.getJoinedPlayers());
				sb.append("\n");
				sb.append(g.getSTATEMsg());
				g.addPlayer(p);
				return sb.toString();
			} else if (str[2].equalsIgnoreCase("STATE")) {
				try {
					if (str[3].equalsIgnoreCase(GameState.STARTED.toString())) {
						Game g = p.getCurrentGame();
						if (g == null)
							return "ERROR\n0:WOOT?";
						if (p != g.getOwner())
							return "ERROR\n0:Not host.";
						if (g.getGameState() != GameState.READY)
							return "ERROR\n4:Players not ready!";
						g.setGameState(GameState.STARTED);
						g.sendMsgToAll(g.getSTATEMsg());
					} else if (str[3].equalsIgnoreCase(GameState.ENDED.toString())) {
						Game g = p.getCurrentGame();
						if (g == null)
							return "ERROR\n0:WOOT?";
						if (p != g.getOwner())
							return "ERROR\n0:Not host.";
						g.setGameState(GameState.ENDED);
						g.sendMsgToAll(g.getSTATEMsg());
						g.removeAllPlayers();
						this.gamesManager.deleteGame(g.getName());
					} else {
						p.setState(GameState.valueOf(str[3]));
						Game g = p.getCurrentGame();
						if (g == null)
							return "ERROR\n0:Not connected to game.";
						g.playerStatusChanged();
					}
				} catch (Exception ex) {
					return "ERROR\n0:Unknown state.";
				}
			} else if (str[2].equalsIgnoreCase("TEAM SCORE")) {
				Game g = p.getCurrentGame();
				if (g == null)
					return "ERROR\n0:WOOT?";
				if (p != g.getOwner())
					return "ERROR\n0:Not host.";
				try {
					int a = Integer.parseInt(str[3]);
					if (a == 0)
						g.incScoreA();
					else
						g.incScoreB();
				} catch (NumberFormatException ex) {
					return "ERROR\n0:Error in data.";
				}
				g.setGameState(GameState.READY);
				g.sendMsgToAll(g.getSTATEMsg());
				g.sendMsgToAll(g.getSCOREMsg());
			}
		} else if (str[0].equalsIgnoreCase("GAMES")) {
			return this.gamesManager.getGamesMsg();
		} else if (str[0].equalsIgnoreCase("CID")) {
			long cid = -1;
			try {
				cid = Long.parseLong(str[1]);
			} catch (NumberFormatException ex) {
				return "ERROR\n1:Could not veryfy CID";
			}
			Player p = this.playerManager.getPlayerById(cid);
			if (p == null) {
				p = new Player(cid, con);
				this.playerManager.addPlayer(p);
			} else {
				if (!p.isDisconnected())
					return "ERROR\n1:Player not disconnected n00b!";
				p.setDisconnected(false);
				p.setTimeout(-1);
				p.setConection(con);
			}
			return p.getCIDMsg();
		} else {
			return "ERROR\n0:Unknow Request. Or no PLAYER message.";
		}
		return null;
	}
}
